package jmp.client.player;

import java.util.*;
import java.io.*;
import javax.sound.sampled.*;

import jmp.client.event.*;
import jmp.client.util.*;

public class MusicPlayer {

    private List<Musica> playlist;
    private List<MusicPlayerListener> ouvintes;
    private int musicaAtual;
    private ObjectOutputStream saida;
    private ObjectInputStream entrada;
    private boolean repetir,  ordemAleatoria;
    
    public MusicPlayer() {
        playlist = new ArrayList<Musica>();
        ouvintes = new ArrayList<MusicPlayerListener>();
        this.musicaAtual = 0;
        this.repetir = false;
        this.ordemAleatoria = false;
    }

    public void setRepetir(boolean repetir) {
        this.repetir = repetir;

        if (this.repetir) {
            this.setOrdemAleatoria(false);
        }
    }

    public void setOrdemAleatoria(boolean ordemAleatoria) {
        this.ordemAleatoria = ordemAleatoria;

        if (this.ordemAleatoria) {
            this.setRepetir(false);
        }
    }

    public boolean isOrdemAleatoria() {
        return this.ordemAleatoria;
    }

    public boolean isRepetir() {
        return this.repetir;
    }

    public List<Musica> getPlaylist() {
        return this.playlist;
    }

    public Musica getMusicaAtual() {
        return playlist.get(this.musicaAtual);
    }

    public void addMusica(Musica m) {
        this.addMusica(playlist.size(), m);
    }

    public void addMusica(int index, Musica m) {
        playlist.add(index, m);
        this.registrarEventos(m);
        this.fireMusicaAdicionada(new MusicPlayerEvent(m));
    }

    public void removeMusica(int index) {
        Musica m = playlist.get(index);
        playlist.remove(index);
        this.registrarEventos(m);
        this.fireMusicaRemovida(new MusicPlayerEvent(m));
    }
    
    public void continuar() throws LineUnavailableException, IOException{
        Musica m = playlist.get(this.musicaAtual);
        
        if(m.getEstadoMusica().equals(Estado.PAUSE)){
            m.play();
        }
    }

    public void play() throws IOException, LineUnavailableException {
        Musica m = playlist.get(this.musicaAtual);
        
        if (playlist.size() > 0 && m.getEstadoMusica().equals(Estado.STOP)) {
            m.play();
        }
    }
    
    public void play(int index) throws IOException, LineUnavailableException, UnsupportedAudioFileException {
        if (playlist.size() > index) {
            this.stop();
            this.musicaAtual = index;
            this.play();
        }
    }

    public void stop() throws IOException, LineUnavailableException, UnsupportedAudioFileException {
        Musica m = playlist.get(this.musicaAtual);
        
        if (playlist.size() > 0 && m.getEstadoMusica().equals(Estado.PLAY)) {
            m.stop();
        }
    }

    public void proxima() throws IOException, LineUnavailableException, UnsupportedAudioFileException {
        this.stop();

        if (this.musicaAtual <= playlist.size() - 2) {
            this.musicaAtual++;
        } else {
            this.musicaAtual = 0;
        }

        this.fireMusicaAlterada(new MusicPlayerEvent(playlist.get(musicaAtual)));
        this.play();
    }

    public void anterior() throws IOException, LineUnavailableException, UnsupportedAudioFileException {
        this.stop();

        if (this.musicaAtual > 0) {
            this.musicaAtual--;
        } else {
            this.musicaAtual = playlist.size() - 1;
        }

        this.fireMusicaAlterada(new MusicPlayerEvent(playlist.get(musicaAtual)));
        this.play();
    }

    public void novaPlaylist() {
        playlist = new ArrayList<Musica>();
    }

    public void pause() {
        playlist.get(this.musicaAtual).pause();
    }
    
    public Estado getEstadoMusica(){
        return playlist.get(this.musicaAtual).getEstadoMusica();
    }

    public void salvarPlaylist(File arquivo) throws IOException, FileNotFoundException {
        //arquivo.renameTo(new File(arquivo.getName() + ".jmp"));
        
        saida = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(arquivo)));

        List<File> lista = new ArrayList<File>();
        for (Musica m : playlist) {
            lista.add(m.getArquivo());
        }

        saida.writeObject(lista);
        saida.close();
    }

    public void abrirPlaylist(File arquivo) throws IOException, FileNotFoundException,
            ClassNotFoundException, UnsupportedAudioFileException, LineUnavailableException {

        entrada = new ObjectInputStream(new BufferedInputStream(new FileInputStream(arquivo)));

        List<File> lista = (List<File>) entrada.readObject();

        playlist = new ArrayList<Musica>();
        for (File f : lista) {
            playlist.add(new Musica(f));
        }

        entrada.close();
    }

    private void registrarEventos(Musica m) {
        m.addMusicListener(new MusicListener() {

            public void comecou(MusicEvent evt) {
                fireMusicaAtualComecou(new MusicPlayerEvent(evt.getMusicaAtual()));
            }

            public void terminou(MusicEvent evt) {
                try {
                    fireMusicaAtualTerminou(new MusicPlayerEvent(evt.getMusicaAtual()));
                    if (repetir) {
                        stop();
                        play();
                    } else if (ordemAleatoria) {
                        stop();
                        musicaAtual = (int) (Math.random() * playlist.size() - 1);
                        play();
                    } else {
                        proxima();
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                } catch (LineUnavailableException ex) {
                    ex.printStackTrace();
                } catch (UnsupportedAudioFileException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }
    
    public void addMusicPlayerListener(MusicPlayerListener ouvinte){
        ouvintes.add(ouvinte);
    }
    
    public void removeMusicPlayerListener(MusicPlayerListener ouvinte){
        ouvintes.remove(ouvinte);
    }
    
    private void fireMusicaAlterada(MusicPlayerEvent evt){
        for(MusicPlayerListener ouvinte : this.ouvintes){
            ouvinte.musicaAlterada(evt);
        }
    }
    
    private void fireMusicaAdicionada(MusicPlayerEvent evt){
        for(MusicPlayerListener ouvinte : this.ouvintes){
            ouvinte.musicaAdicionada(evt);
        }
    }
    
    private void fireMusicaRemovida(MusicPlayerEvent evt){
        for(MusicPlayerListener ouvinte : this.ouvintes){
            ouvinte.musicaRemovida(evt);
        }
    }
    
    private void fireMusicaAtualComecou(MusicPlayerEvent evt){
        for(MusicPlayerListener ouvinte : this.ouvintes){
            ouvinte.musicaAtualComecou(evt);
        }
    }
    
    private void fireMusicaAtualTerminou(MusicPlayerEvent evt){
        for(MusicPlayerListener ouvinte : this.ouvintes){
            ouvinte.musicaAtualTerminou(evt);
        }
    }
}
